<template>
    <h1>Game1</h1>
    <div class="container" ref="ContainerRef" :style="{ width: size.width + 'px', height: size.height + 'px' }"></div>
</template>

<script setup lang="ts" name="game1">
import { onUnmounted, ref } from 'vue';
import DefaultScene from '../libs/scene2'
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { Octree } from 'three/examples/jsm/math/Octree.js';
import { Capsule } from 'three/examples/jsm/math/Capsule.js';
const WorldGlb = '/glb/collision-world.glb';
const PeopleGlb = '/glb/Soldier.glb'

const defaultScene = new DefaultScene();
const {scene, renderer, camera, controls, size} = defaultScene;


/**
 * 初始化
 */
const ContainerRef = ref();
defaultScene.init(ContainerRef);
// scene.add(axesHelper);

renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.VSMShadowMap;
/**
 * 业务相关
 */
controls.enableRotate = false; // 禁止控制器旋转
// 添加一个环境光

const ambient = new THREE.AmbientLight(0xffffff, 1);
scene.add(ambient);
camera.position.set(0.1, 0.1, 0.1);
scene.background = new THREE.Color(0x00ccff)

const directionalLight = new THREE.DirectionalLight(0xffffff, 3);
directionalLight.position.set(13.2, 37.6, 23.2);
directionalLight.castShadow = true;
directionalLight.shadow.camera.near = 0.01;
directionalLight.shadow.camera.far = 500;
directionalLight.shadow.camera.right = 30;
directionalLight.shadow.camera.left = - 30;
directionalLight.shadow.camera.top = 30;
directionalLight.shadow.camera.bottom = - 30;
directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;
directionalLight.shadow.radius = 4;
directionalLight.shadow.bias = - 0.00006;
scene.add(directionalLight);

const dirHelper = new THREE.DirectionalLightHelper(directionalLight, 5);
scene.add(dirHelper);

const loader = new GLTFLoader();
const worldOctree: Octree = new Octree();

const loadMap = () => {
    loader.load(WorldGlb, function (gltf) {
        // 返回的场景对象gltf.scene插入到threejs场景中
        gltf.scene.traverse(function (obj: any) {
            if (obj.isMesh) { //判断是否是网格模型
                // 批量设置所有Mesh都可以产生阴影和接收阴影
                obj.castShadow = true;
                obj.receiveShadow = true;
                if (obj.material.map) {
                    obj.material.map.anisotropy = 4;
                }
            }
        });
        // console.log('gltf.scene', gltf.scene);
        scene.add(gltf.scene);
        worldOctree.fromGraphNode(gltf.scene);
        // const helper = new OctreeHelper(worldOctree);
        // scene.add(helper);
    })
}

interface PersonProps {
    idleAction?: THREE.AnimationAction;
    walkAction?: THREE.AnimationAction;
    runAction?: THREE.AnimationAction;
    mesh: THREE.Object3D,
    capsule?: Capsule,
    capsuleHelper?: THREE.Object3D
}

const personObj: PersonProps = {
    mesh: new THREE.Group()
}
scene.add(personObj.mesh);
scene.remove(camera);
const mixer = new THREE.AnimationMixer(scene);

onUnmounted(() => {
    defaultScene.stopLoop();
})

const loadPerson = () => {
    loader.load(PeopleGlb, (gltf) => {
        gltf.scene.castShadow = true;
        gltf.scene.receiveShadow = true;
        gltf.scene.rotateY(Math.PI); // 旋转人物角度使之与z轴正方向对齐
        gltf.scene.scale.set(0.1, 0.1, 0.1);
        console.log('gltf.scene', gltf.scene);
        personObj.mesh.position.y = -0.15;
        personObj.mesh.add(gltf.scene);
        personObj.mesh.add(camera);
        camera.position.set(0, 0.15, -0.25); //相机放在人后面的位置
        camera.lookAt(0, 0, 0);  // 相机朝向personObj.mesh原点
        let vec = new THREE.Vector3()
        personObj.mesh.getWorldDirection(vec); // 获取模型在世界坐标上的方向
        const animations = gltf.animations;
        personObj.idleAction = mixer.clipAction(animations[0]);
        personObj.walkAction = mixer.clipAction(animations[3]);
        personObj.runAction = mixer.clipAction(animations[1]);
        personObj.idleAction.play()
        personObj.walkAction.play()
        personObj.runAction.play()
        personObj.idleAction.weight = 1.0;
        personObj.walkAction.weight = 0.0;
        personObj.runAction.weight = 0.0;
        const box3 = new THREE.Box3()
        box3.expandByObject(gltf.scene);
        const size = box3.getSize(new THREE.Vector3());
        const R = Math.max(size.x, size.z);
        const H = 0.18;
        personObj.capsule = new Capsule(new THREE.Vector3(0, R, 0), new THREE.Vector3(0, H - R, 0), R);
        // personObj.capsuleHelper = CapsuleHelper(R, H);
        personObj.mesh.position.y -= 1.6;
        // scene.add(personObj.capsuleHelper);
        const initPos = personObj.mesh.getWorldPosition(new THREE.Vector3());
        personObj.capsule.translate(initPos);
        // personObj.capsuleHelper.position.add(initPos);
    })
}

/**
 * 按键状态
 */
const keyStates: any = {

}
// 当某个键盘按下设置对应属性设置为true
document.addEventListener('keydown', (event) => {
    keyStates[event.code] = true;
    if (event.code == 'KeyW' || event.code == 'KeyS') {
        personObj.idleAction!.weight = 0.0;
        personObj.walkAction!.weight = 1.0;
        personObj.runAction!.weight = 0.0;
    }
});
// 当某个键盘抬起设置对应属性设置为false
document.addEventListener('keyup', (event) => {
    keyStates[event.code] = false;
    if (event.code == 'KeyW' || event.code == 'KeyS') {
        personObj.idleAction!.weight = 1.0;
        personObj.walkAction!.weight = 0.0;
        personObj.runAction!.weight = 0.0;
    }
});
const clock = new THREE.Clock();

const checkIntersect = () => {
    if (!personObj.capsule) return false;
    let result = worldOctree.capsuleIntersect(personObj.capsule);
    if (result) { // 发生碰撞了就向碰撞方向反向移动
        personObj.capsule.translate(result.normal.multiplyScalar(result.depth));
        return true;
    } else { // 没有发生碰撞按照重力方向往下掉, 再计算一次碰撞
        const vec = new THREE.Vector3(0, -0.01, 0);
        personObj.capsule.translate(vec);
        let result = worldOctree.capsuleIntersect(personObj.capsule);
        if (result) { // 发生碰撞了就向恢复当前状态
            personObj.capsule.translate(new THREE.Vector3(0, 0.01, 0));
        }
    }
    return false;
}

// 动画循环
const animate = () => {
    const deltaTime = clock.getDelta();
    if (!personObj.mesh || !personObj.capsule) {
        return;
    }
    if (keyStates['KeyW']) { // 前进
        const vec = new THREE.Vector3();
        personObj.mesh.getWorldDirection(vec);
        const deltaPos = vec.clone().multiplyScalar(deltaTime);
        personObj.capsule.translate(deltaPos);//更新玩家角色的位置
    } else if (keyStates['KeyS']) { // 后退
        const vec = new THREE.Vector3();
        personObj.mesh.getWorldDirection(vec);
        const deltaPos = vec.clone().multiplyScalar(-deltaTime);
        personObj.capsule.translate(deltaPos);//更新玩家角色的位置
    }
    if (keyStates['KeyA']) { // 旋转
        personObj.mesh.rotateY(deltaTime);
    } else if (keyStates['KeyD']) { // 旋转
        personObj.mesh.rotateY(-deltaTime);
    }
    if ( keyStates[ 'Space' ] ) {
        personObj.capsule.translate(new THREE.Vector3(0, 0.1, 0));
    }
    mixer.update(deltaTime);
    checkIntersect();
    personObj.mesh.position.copy(personObj.capsule.start);
    // personObj.capsuleHelper?.position.copy(personObj.capsule.start)
}
defaultScene.addLoops(animate); // 加入主动画循环
// 加入物理引擎cannon
(async () => {
    loadMap();
    loadPerson()
})();

</script>